home *** CD-ROM | disk | FTP | other *** search
- #define C
-
- #undef PROFILE
- #define COUNT
-
- /********************************************************************
- FILENAME: VIEW.CPP
- AUTHOR : JAKE HILL
- DATE : 12/1/94
-
- Copyright (c) 1994 by Jake Hill:
- If you use any part of this code in your own project, please credit
- me in your documentation and source code. Thanks.
- ********************************************************************/
-
- #include "view.h"
- #include "trig.h"
-
- #ifdef __GNUC__
- #include <osbind.h>
- #include <memory.h>
- #else
- #include <tos.h>
- #endif
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define SKY_COLOR 1
- #define FLOOR_COLOR 2
- #define WALL_COLOR 3
- #define RED_COLOR 4
- #define LEDGE_COLOR 5
- #define ZMIN 20L
-
- #define UPPER_TYPE 0
- #define WALL_TYPE 1
- #define LOWER_TYPE 2
-
- #ifdef C
- extern char hash(side *, int);
- extern char OnRightNode(short node_num);
- extern char OnRightLine(short from, short to);
- extern char LeftSideInCone(short node_num);
- extern char RightSideInCone(short node_num);
- extern void draw_line(short, short, short);
- void DrawNode(short node_num);
- void DrawSSector(short SS);
- #ifdef __GNUC__
- void LoadSeg(short seg);
- #else
- void LoadSeg(short xseg);
- #endif
- void AddWall(short sx1, short sx2, short Rb, short Rt, short Rfz, short Rtz);
- extern void DrawSegs(void);
- #if 0
- void AddFloorUp(short lb, short b, short start, short type);
- void AddFloorDown(short lb, short b, short start, short type);
- void EndFloorUp(short lb, short b, short end);
- void EndFloorDown(short lb, short b, short end);
- #endif
- #endif
-
- extern short width;
- extern short height;
-
- extern short flooropt;
- extern short floorcol;
- extern short nofloor;
- extern short wallopt;
- extern short wallcol;
- extern short singlestep;
- extern short showdata;
- extern short draw_2D;
-
- #ifdef COUNT
- extern long drawview;
-
- extern long addfloor;
- extern long addfloor_loops;
-
- extern long addwall;
- extern long addwall_loops;
-
- extern long coldraw;
- extern long coldraw_loops;
-
- extern long rowdraw;
- extern long rowdraw_loops;
-
- extern long drawnode;
- extern long drawssector;
- extern long drawssector_loops;
- extern long loadseg;
- extern long loadseg_loops1;
- extern long loadseg_loops2;
-
- extern long setuptime;
- extern long drawtime;
- extern long c2ptime;
- #endif
-
- /* These are some yucky global variables. They should probably
- * be moved into the class's member data.
- */
- extern short ColCount;
- extern short WallCount;
- extern short WallRunCount;
- extern short FirstSSector;
-
- #if 0
- extern short player_ssector;
- #endif
-
- /* Elements of this array indicate if a screen column is completely drawn. */
-
- #if 0
- extern short Col_Done[320];
- #endif
- extern char Col_Done[320]; /* Slightly better for the cache */
-
-
- /* Elements of this array hold indexes into the wall_run array. */
-
- #if 1
- extern short intersections[50][320];
- #endif
-
- /* The number of wall_runs visible on a particular screen column. */
-
- #if 1
- extern short int_count[320];
- #endif
-
- /* MaxY & MinY are the active edge lists for the top & bottom of the screen. */
-
- extern short MaxY[320];
- extern short MinY[320];
-
-
- /* This is the wall_run array. It contains all of the wall_runs which
- * are visible in a single frame.
- */
-
- #if 1
- extern wall_run walls[8000]; /* 320*50 = 16000 */
- #endif
-
- extern short walltop[320];
- extern short wallbottom[320];
-
- /* The next two arrays are used for both floors and ceilings.
- * Elements of this array hold indexes into the floor_run array.
- */
-
- #if 1
- extern floor_run floorlist[200][40];
- #endif
-
- extern short floorlst[200];
- extern short floortex[200];
-
- /* The number of floor_runs visible on a particular screen column. */
-
- extern short runcount[200];
-
-
- /* The offscreen buffer. */
- extern char *screenbuf;
-
-
- extern void c2p(char *buf, int w_area, int h_area);
- extern char hash(side *ThisSide, int wall_type);
- extern long get_timer(void);
-
- void DrawNode(short node_num)
- {
- #ifdef COUNT
- drawnode++;
- #endif
-
- /* If this node is a SSECTOR then we need to render it. */
-
- if (node_num & 0x8000) {
- DrawSSector(node_num & 0x7fff);
- return;
- }
-
- /* Once we have rendered 319 columns then we are done,
- * so lets stop recursing.
- */
-
- if (ColCount > width - 2)
- return;
-
- if (!OnRightNode(node_num)) {
- if (LeftSideInCone(node_num))
- DrawNode(PNode_Array[node_num]->left);
- if (RightSideInCone(node_num))
- DrawNode(PNode_Array[node_num]->right);
- } else {
- if (RightSideInCone(node_num))
- DrawNode(PNode_Array[node_num]->right);
- if (LeftSideInCone(node_num))
- DrawNode(PNode_Array[node_num]->left);
- }
- }
-
-
- /* This function obtains data common to all segs in the SSector
- * as well as doing the backface elimination via OnRight.
- */
-
- void DrawSSector(short SS)
- {
- short i;
- short LineSide, Sector;
- short SegCount, FirstSeg;
- segment *ThisSeg;
- sector *ThisSector;
-
- /* Load FirstSeg and SegCount locally for speed improvement. */
-
- FirstSeg = SSector_Array[SS].first_seg;
- SegCount = SSector_Array[SS].num_segs;
-
- #ifdef COUNT
- drawssector++;
- drawssector_loops += SegCount;
- #endif
-
- ThisSeg = &Seg_Array[FirstSeg];
-
- LineSide = ThisSeg->line_side;
-
- #ifdef __GNUC__
- Sector = Side_Array[Line_Array[ThisSeg->line].side[LineSide]].sector;
- #else
- Sector = Side_Array[Line_Array[ThisSeg->xline].side[LineSide]].sector;
- #endif
-
- /* Load the floor and ceiling height. */
-
- ThisSector = &Sector_Array[Sector];
- floor_ht = ThisSector->floor_ht;
- ceiling_ht = ThisSector->ceiling_ht;
-
- /* Here we determine the viewers height relative to all the walls, etc. */
-
- if (FirstSSector) {
- FirstSSector = 0;
- Pz = Ph + floor_ht;
- #if 0
- /* ThisSector might be better below */
- player_ssector = SS; /* Used to stop wall pass-through */
- #endif
- }
-
- /* Draw each SEG in the SSECTOR which can be seen. */
-
- for (i = 0;i < SegCount;i++) {
- if (OnRightLine(ThisSeg->from, ThisSeg->to)) {
- if (!draw_2D || wallcol)
- LoadSeg(FirstSeg + i);
- else
- draw_line(ThisSeg->from, ThisSeg->to, 0xff);
- }
- ThisSeg++;
- }
- }
-
-
- /* This function is where all of the Rotations and Transformations
- * are done. This is my very first 3D program, so there is probably
- * a LOT here which can be optimized for speed.
- */
-
- #ifdef __GNUC__
- void LoadSeg(short seg)
- #else
- void LoadSeg(short xseg)
- #endif
- {
- #ifdef __GNUC__
- segment *ThisSeg = &Seg_Array[seg];
- #else
- segment *ThisSeg = &Seg_Array[xseg];
- #endif
- short To = ThisSeg->to;
- short From = ThisSeg->from;
- unsigned short Angle = ThisSeg->angle - Pangle;
- char ch;
- vertex *Vertex;
- short Wfx, Wfy;
- short Wtx, Wty;
- long Rfz, Rtz;
- long Rfx, Rtx;
- long TanAngle;
- long XZ;
- short x1, x2, sx1, sx2;
- char ExitNow;
- int x;
- short Rt, Rb;
- short SingleSided;
- short Side;
- line *ThisLine;
- side *ThisSide, *ThatSide;
-
- #ifdef COUNT
- loadseg++;
- #endif
-
- /* Store the World Space Coordinates */
-
- Vertex = &Vertex_Array[To];
- Wtx = Vertex->x;
- Wty = Vertex->y;
-
- Vertex = &Vertex_Array[From];
- Wfx = Vertex->x;
- Wfy = Vertex->y;
-
- /* Rotate the World Space Coordinates relative to player. */
-
- Rfz = (((Wfx - Px) * CosPangle) - ((Wfy - Py) * SinPangle)) >> 16;
- Rtz = (((Wtx - Px) * CosPangle) - ((Wty - Py) * SinPangle)) >> 16;
-
- /* If the seg is completely behind the player, exit the fn. */
-
- if ((Rfz < ZMIN) && (Rtz < ZMIN)) {
- if (draw_2D)
- draw_line(From, To, 1);
- return;
- }
- /* Finish rotating the coordinates. */
-
- Rfx = (((Wfx - Px) * SinPangle) + ((Wfy - Py) * CosPangle)) >> 16;
- Rtx = (((Wtx - Px) * SinPangle) + ((Wty - Py) * CosPangle)) >> 16;
-
- /* Perform Z-clipping if necessary. */
-
- TanAngle = tangent(Angle);
-
- #if 0
- if (ch != 'x') {
- if (Rfx > Rfz) { /* Clip Rfx, Rfz to line x = z. */
- if (wallopt && flooropt && (ch == 's')) {
- printf("Clip Rfx/z to x = z\n");
- }
- if (TanAngle == 65536L) /* Prevent a divide by zero. */
- return;
- long XZ = ((Rfx << 16) - (Rfz * TanAngle)) / (65536L - TanAngle);
- Rfx = Rfz = XZ;
- }
- /* Just a test below */
- if (Rtx > Rtz) { /* Clip Rtx, Rtz to line x = z. */
- if (wallopt && flooropt && (ch == 's')) {
- printf("Clip Rtx/z to x = z\n");
- }
- if (TanAngle == 65536L) /* Prevent a divide by zero. */
- return;
- XZ = ((Rtx << 16) - (Rtz * TanAngle)) / (65536L - TanAngle);
- Rtx = Rtz = XZ;
- }
- }
- #endif
- if (Rfz < ZMIN) { /* Clip Rfx, Rfz to zmin. */
- if (wallopt && flooropt && (ch == 's')) {
- printf("Clip Rfx/z to ZMIN\n");
- }
- Rfx = Rfx + (((ZMIN - Rfz) * TanAngle) >> 16);
- Rfz = ZMIN;
- }
- if (Rtz < ZMIN) { /* Clip Rtx, Rtz to zmin. */
- if (wallopt && flooropt && (ch == 's')) {
- printf("Clip Rtx/z to ZMIN\n");
- }
- Rtx = Rtx + (((ZMIN - Rtz) * TanAngle) >> 16);
- Rtz = ZMIN;
- }
-
- if (Rfz > 9999L) { /* We don't want to go out of */
- Rfz = 9999L;
- if (wallopt && flooropt && (ch == 's')) {
- printf("Clipping Rfz\n");
- }
- }
- if (Rtz > 9999L) { /* bounds with these values. */
- Rtz = 9999L;
- if (wallopt && flooropt && (ch == 's')) {
- printf("Clipping Rtz\n");
- }
- }
-
- /* Project the World Space -X- Coordinates to screen space coordinates.
- * MAKE SURE that Z-Clipping is done before this or we may get a
- * negative value for Rfz or Rtz - this would be out of bounds.
- */
-
- sx1 = x1 = (short)((long)width / 2 - ((Rfx * invdistance(Rfz)) >> 16));
- sx2 = x2 = (short)((long)width / 2 - ((Rtx * invdistance(Rtz)) >> 16));
-
- /* Check if wall segment is on screen or is wide enough to see. */
-
- if (sx2 <= 0) {
- #if 0
- if (sx2 == 0)
- printf("sx2 <= 0\n");
- #endif
- if (draw_2D)
- draw_line(From, To, 2);
- return;
- }
- if (sx1 > width - 1) {
- if (draw_2D)
- draw_line(From, To, 2);
- return;
- }
- if (sx1 == sx2) {
- #if 0
- printf("sx1 == sx2\n");
- #endif
- if (draw_2D)
- draw_line(From, To, 2);
- return;
- }
-
- /* Check if wall segment is completely occluded. */
-
- if (x1 < 0)
- x1 = 0;
- if (x2 > width)
- x2 = width;
-
- ExitNow = 1;
- for(x = x1;x < x2;x++)
- if (Col_Done[x] == 0) {
- ExitNow = 0;
- break;
- }
- #ifdef COUNT
- loadseg_loops1 += x - x1;
- #endif
-
- if (ExitNow) {
- if (draw_2D)
- draw_line(From, To, 3);
- return;
- }
- if (singlestep) {
- ch = Cnecin();
- }
-
- if (draw_2D)
- draw_line(From, To, 0xff);
-
- if (singlestep && (ch == 'c')) {
- printf("2D (%d,%d) -> (%d,%d)\n", Wfx, Wfy, Wtx, Wty);
- printf("Z %ld -> %ld\n", Rfz, Rtz);
- printf("X %ld -> %ld (%d->%d)\n", Rfx, Rtx, x1, x2);
- printf("MaxY[%d] = %d, MinY[%d] = %d\n", x1, MaxY[x1], x1, MinY[x1]);
- printf("MaxY[%d] = %d, MinY[%d] = %d\n", x2, MaxY[x2], x2, MinY[x2]);
- }
-
- /**************************************************************
- * Calculate the screen coordinates of the wall segment.
- **************************************************************/
-
- #ifdef __GNUC__
- SingleSided = !(Line_Array[ThisSeg->line].flags & 0x0004);
- #else
- SingleSided = !(Line_Array[ThisSeg->xline].flags & 0x0004);
- #endif
-
- Side = ThisSeg->line_side;
- #ifdef __GNUC__
- ThisLine = &Line_Array[ThisSeg->line];
- #else
- ThisLine = &Line_Array[ThisSeg->xline];
- #endif
- ThisSide = &Side_Array[ThisLine->side[Side]];
- Wall.opaque = 0;
-
- /* If there is a main_tx then there will not be an upper
- * or lower, so we can exit when done with this.
- */
-
- if (ThisSide->main_tx[0] != '-') {
- Rb = Pz - floor_ht;
- Rt = Pz - ceiling_ht;
-
- Wall.type = WALL_TYPE;
- Wall.tex_code = hash(ThisSide, WALL_TYPE); /* Added by Johan */
- AddWall(sx1, sx2, Rb, Rt, (short)Rfz, (short)Rtz);
-
- if (singlestep && (wallopt || flooropt)) {
- c2p(screenbuf, width, height);
- }
-
- if (SingleSided) {
- Wall.opaque = 1;
- #ifdef COUNT
- loadseg_loops2 += x2 - x1;
- #endif
- for(x = x1;x < x2;x++)
- if (Col_Done[x] == 0) {
- ColCount++;
- Col_Done[x] = 1;
- }
- }
- return;
- }
-
- /* If there is not a main_tx then there will be both an
- * upper_tx, and a lower_tx. One or both may have a height of zero.
- */
-
- ThatSide = &Side_Array[ThisLine->side[!Side]];
-
- if (ThisSide->lower_tx[0] != '-')
- Rt = Pz - Sector_Array[ThatSide->sector].floor_ht;
- else
- Rt = Pz - floor_ht;
-
- Rb = Pz - floor_ht;
- Wall.type = LOWER_TYPE;
- Wall.tex_code = hash(ThisSide, LOWER_TYPE); /* Added by Johan */
- AddWall(sx1, sx2, Rb, Rt, (short)Rfz, (short)Rtz);
-
- if (singlestep && (wallopt || flooropt)) {
- c2p(screenbuf, width, height);
- }
-
- if (ThisSide->upper_tx[0] != '-')
- Rb = Pz - Sector_Array[ThatSide->sector].ceiling_ht;
- else
- Rb = Pz - ceiling_ht;
-
- Rt = Pz - ceiling_ht;
- Wall.type = UPPER_TYPE;
- Wall.tex_code = hash(ThisSide, UPPER_TYPE); /* Added by Johan */
- AddWall(sx1, sx2, Rb, Rt, (short)Rfz, (short)Rtz);
-
- if (singlestep && (wallopt || flooropt)) {
- c2p(screenbuf, width, height);
- }
- }
-
-